﻿using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using AgFractal.Coloring;

namespace AgFractal.Controls.GradientEditor
{
    public partial class GradientEditor : PopupUserControl
    {
        private List<ColorEntry> colorEntries = new List<ColorEntry>();

        public GradientEditor()
        {
            InitializeComponent();
        }

        Gradient gradient;
        internal void SetGradient(Gradient gradient)
        {
            this.gradient = gradient;
            UpdateThumbs(0);
        }

        void UpdateThumbs(int activeIdx)
        {
            foreach (var thumb in gradientGrid.Children.OfType<Thumb>().ToList())
                gradientGrid.Children.Remove(thumb);

            colorEntries = gradient.Entries.OrderBy(i => i.Idx).ToList();
            foreach (var ce in colorEntries)
            {
                var thumb = new Thumb { ColorEntry = ce };
                WireThumb(thumb);

                var idx = colorEntries.IndexOf(ce);

                if (activeIdx == ce.Idx)
                    SetActiveThumb(thumb);

                if (idx == 0 || (idx == colorEntries.Count - 1))
                    thumb.Move(ce.Idx);
                else
                    thumb.Move(margin + ce.Idx);
                thumb.SetValue(Grid.RowProperty, 1);
                gradientGrid.Children.Add(thumb);
            }
            RepaintGradientImage();
        }

        Thumb activeThumb;
        void SetActiveThumb(Thumb thumb)
        {
            if (activeThumb != null)
                activeThumb.IsActive = false;
            activeThumb = thumb;
            thumb.IsActive = true;
            cp1.SelectedColor = thumb.ColorEntry.Color;
            var activeIdx = thumb.ColorEntry.Idx;
            deleteBtn.IsEnabled = !(activeIdx == 0 || (activeIdx == colorEntries.Count - 1));
        }

        private void WireThumb(Thumb thumb)
        {
            thumb.MouseLeftButtonDown += firstThumb_MouseLeftButtonDown;
            thumb.MouseLeftButtonUp += firstThumb_MouseLeftButtonUp;
            thumb.MouseMove += firstThumb_MouseMove;
        }

        bool dragging;
        void firstThumb_MouseMove(object sender, MouseEventArgs e)
        {
            if (!dragging)
                return;

            var thumb = (Thumb)sender;

            var pos = e.GetPosition(LayoutRoot);
            var dx = startx + pos.X - startPos.X;

            if (dx >= minx && dx <= maxx)
            {
                thumb.Move(dx);
                var ce = thumb.ColorEntry;
                ce.Idx = (int)dx;
                gradient.CalcColors();
                RepaintGradientImage();
            }
        }

        const double margin = 0;
        void firstThumb_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            Cursor = Cursors.Arrow;
            dragging = false;
            var thumb = (Thumb)sender;
            thumb.ReleaseMouseCapture();
            var pos = e.GetPosition(LayoutRoot);
            if (pos.Y - startPos.Y > 20)
                DeleteThumb();
        }

        Point startPos;
        double minx, maxx;
        double startx;
        void firstThumb_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            startPos = e.GetPosition(LayoutRoot);
            Cursor = Cursors.Hand;
            var thumb = (Thumb)sender;
            SetActiveThumb(thumb);
            var ce = thumb.ColorEntry;
            var idx = colorEntries.IndexOf(ce);

            if (idx == 0 || (idx == colorEntries.Count - 1))
                return;

            startx = thumb.GetX();
            thumb.CaptureMouse();
            dragging = true;

            if (idx == 0)
                minx = 0;
            else
                minx = colorEntries[idx - 1].Idx;
            minx += 10;

            if (idx == colorEntries.Count)
                maxx = ce.Idx;
            else
                maxx = colorEntries[idx + 1].Idx;

            maxx -= 10;
        }

        private void ColorChanged(object sender, SilverlightContrib.Controls.SelectedColorEventArgs e)
        {
            activeThumb.SetColor(e.SelectedColor);
            var ce = activeThumb.ColorEntry;
            ce.Color = e.SelectedColor;
            gradient.CalcColors();
            RepaintGradientImage();
        }

        private void RepaintGradientImage()
        {
            var colors = gradient.Colors;
            var png = new PngEncoder(colors.Count, 150);

            for (int Y = 0; Y < 150; Y++)
            {
                var start = png.GetRowStart(Y);
                for (int X = 0; X < colors.Count; X++)
                {
                    png.SetPixelAtRowStart(X, start,
                        colors[X].R, colors[X].G, colors[X].B, 255);
                }
            }
            img.Source = png.GetImageSource();
        }

        private void img_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            var pos = e.GetPosition(img);
            int idx = (int)pos.X;

            foreach (var ce in colorEntries)
                if (ce.Idx + 20 > idx && ce.Idx - 20 < idx)
                    return;
            gradient.Entries.Add(new ColorEntry { Idx = idx, Color = gradient.Colors[idx] });
            UpdateThumbs(idx);
        }

        private void OKButton_Click(object sender, RoutedEventArgs e)
        {
            Close(true);
        }

        private void CancelButton_Click(object sender, RoutedEventArgs e)
        {
            Close(false);
        }

        private void ReverseClick(object sender, RoutedEventArgs e)
        {
            var maxIdx = colorEntries.Count - 1;
            for (int i = 0; i < colorEntries.Count/2; i++)
            {
                var tmp = colorEntries[i].Color;
                colorEntries[i].Color = colorEntries[maxIdx- i].Color;
                colorEntries[maxIdx - i].Color = tmp;
            }

            gradient.Entries = colorEntries;
            UpdateThumbs(0);
        }

        private void deleteClick(object sender, RoutedEventArgs e)
        {
            DeleteThumb();
        }

        private void DeleteThumb()
        {
            gradient.Entries.Remove(activeThumb.ColorEntry);
            gradient.CalcColors();
            UpdateThumbs(0);
        }
    }
}